
#ifndef __QYMATH_H__
#define __QYMATH_H__

#include "../common/qyCommon.h"

#include <math.h>
#include <float.h>

#ifdef _WIN32
#   include <malloc.h>
#else
#   include <malloc/malloc.h>
#endif

const float cQY_PI = 3.14159265358979323846f;
const float cDEG2RAD = cQY_PI / 180.0f;
const float cRAD2DEG = 180.0f / cQY_PI;

template<class T> QY_INLINE T	TMax( T x, T y ) { return ( x > y ) ? x : y; }
template<class T> QY_INLINE T	TMin( T x, T y ) { return ( x < y ) ? x : y; }
template<class T> QY_INLINE int	TMaxIndex( T x, T y ) { return  ( x > y ) ? 0 : 1; }
template<class T> QY_INLINE int	TMinIndex( T x, T y ) { return ( x < y ) ? 0 : 1; }

template<class T> QY_INLINE T	TMax3( T x, T y, T z ) { return ( x > y ) ? ( ( x > z ) ? x : z ) : ( ( y > z ) ? y : z ); }
template<class T> QY_INLINE T	TMin3( T x, T y, T z ) { return ( x < y ) ? ( ( x < z ) ? x : z ) : ( ( y < z ) ? y : z ); }
template<class T> QY_INLINE int	TMax3Index( T x, T y, T z ) { return ( x > y ) ? ( ( x > z ) ? 0 : 2 ) : ( ( y > z ) ? 1 : 2 ); }
template<class T> QY_INLINE int	TMin3Index( T x, T y, T z ) { return ( x < y ) ? ( ( x < z ) ? 0 : 2 ) : ( ( y < z ) ? 1 : 2 ); }

inline float Log2( float x ) 
{
	static float invLog2 = 1.f / logf( 2.f );
	return logf(x) * invLog2;
}

inline int Log2Int( float v ) 
{
	return ( (*(int *) &v) >> 23 ) - 127;
}

inline bool IsPowerOf2( int v ) 
{
	return (v & (v - 1)) == 0;
}

inline unsigned int RoundUpPow2( unsigned int v ) 
{
	v--;
	v |= v >> 1;
	v |= v >> 2;
	v |= v >> 4;
	v |= v >> 8;
	v |= v >> 16;
	return v+1;
}

#define _doublemagicroundeps	(.5-1.4e-11)
#define _doublemagic	double (6755399441055744.0)

//almost .5f = .5f - 1e^(number of exp bit)
QY_INLINE int Round2Int( double val ) 
{
	//2^52 * 1.5,  uses limited precision to floor
	val	= val + _doublemagic;
	return ( (long*)&val )[0];
}

QY_INLINE int Float2Int( double val ) 
{
	return ( val < 0 ) ?  Round2Int( val + _doublemagicroundeps ) : Round2Int( val - _doublemagicroundeps );
}

QY_INLINE int Floor2Int( double val ) 
{
	return Round2Int( val - _doublemagicroundeps );
}

QY_INLINE int Ceil2Int(double val) 
{
	return Round2Int( val + _doublemagicroundeps );
}

//-----------------------------------------------------------------------
QY_INLINE void qySinCos( const float a, float &s, float &c )
{
#if 0
	_asm {
		fld		a
		fsincos
		mov		ecx, c
		mov		edx, s
		fstp	dword ptr [ecx]
		fstp	dword ptr [edx]
	}

#else
	s = sinf( a );
	c = cosf( a );
#endif
}

//-----------------------------------------------------------------------
QY_INLINE float qyRSqrt( float x ) 
{
	// NOTE: allows x == 0
	long i;
	float y, r;

	y = x * 0.5f;
	i = *reinterpret_cast<long *>( &x );
	i = 0x5f3759df - ( i >> 1 );
	r = *reinterpret_cast<float *>( &i );
	r = r * ( 1.5f - r * r * y );
	return r;
}

#endif
